import {
    PerspectiveCamera, Scene, WebGLRenderer, Vector3, Object3D, Group,
    Mesh, SphereGeometry, MeshPhongMaterial, Color,
} from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

export default class Stage {
    renderer: WebGLRenderer;
    scene: Scene;
    camera: PerspectiveCamera;
    controls: OrbitControls;
    beforeRender = (time: number) => { };
    onresizeEvent: boolean = true;

    static _stage: Stage;

    private _isAnimate: number = 0;
    private _objMap: Map<string, Object3D> = new Map();

    public constructor(
        width: number = window.innerWidth,
        height: number = window.innerHeight,
        eye: Vector3 = new Vector3(0, 0, 5),
        lookAt: Vector3 = new Vector3(0, 0, 0)
    ) {
        Stage._stage = this;

        this.scene = new Scene();
        this.renderer = new WebGLRenderer({ antialias: true });//抗锯齿
        this.renderer.setSize(width, height, false);

        this.camera = new PerspectiveCamera(45, width / height, 0.1, 1000);
        this.camera.position.copy(eye);
        // this.camera.up.set(0, 0, -1);
        this.camera.lookAt(lookAt);

        this.controls = new OrbitControls(this.camera, this.renderer.domElement);
        this.controls.object.position.set(eye.x, eye.y, eye.z);
        this.controls.target = new Vector3(lookAt.x, lookAt.y, lookAt.z);

        window.addEventListener("resize", this.responsive);
    }

    private responsive() {
        const { renderer, camera, onresizeEvent } = Stage._stage;
        const { width, height, clientWidth, clientHeight } = renderer.domElement;

        if (onresizeEvent == false) return;

        if (width !== clientWidth || height !== clientHeight) {
            //如果为true会设置style的W/H
            renderer.setSize(clientWidth * devicePixelRatio, clientHeight * devicePixelRatio, false);
            camera.aspect = clientWidth / clientHeight;
            camera.updateProjectionMatrix();
        }
    }

    public animate(time: number = 0) {
        const { renderer, scene, camera, beforeRender } = this;
        camera.updateWorldMatrix(true, true);
        beforeRender(time);

        this.controls.update();
        renderer.render(scene, camera);

        requestAnimationFrame((time) => { this.animate(time); });
    }

    public add(Object3D: Object3D, title: string) {
        const { scene, _objMap } = this;
        let group = _objMap.get(title);
        if (!group) {
            group = new Group();
            group.name = title;
            scene.add(group);

            _objMap.set(title, group);
        }
        group.add(Object3D);

    }

    public setCamera(camera: PerspectiveCamera, lookAt: Vector3) {
        this.camera = camera;
        this.camera.updateProjectionMatrix();
        this.controls = new OrbitControls(this.camera, this.renderer.domElement);

        this.controls.target = lookAt;
    }
}